﻿using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Xml;

namespace ErrorDumper.Writing {
    public sealed class EventLogExceptionWriter : IExceptionWriter {

        public const int MaxMessageLength = 31838;

        public static string Source {
            get {
                var source = ExceptionDataSource.Current.EventLogSource;

                if (string.IsNullOrEmpty(source))
                    throw new InvalidOperationException(
                        "Configuration attribute \"eventLogSource\" should be specified in configuration section " +
                        "\"errorDumper/dataSource\".");

                return source;
            }
        }

        public string WriteException(ExceptionPropertyCollection properties, string content) {
            var utc = DateTimeOffset.UtcNow;
            var message = TraceExceptionWriter.ToString(utc, properties, content);

            if (message.Length > MaxMessageLength)
                message = message.Substring(0, MaxMessageLength);

            var source = Source;

            EventLog.WriteEntry(source, message, EventLogEntryType.Error, 0, 0, Encoding.UTF8.GetBytes(content));

            return "eventlog:" + utc.ToString("s");
        }

        public static void Write(string source, Exception exception, string message = null) {
            if (string.IsNullOrEmpty(source))
                throw new ArgumentException("Source should be specified.", "source");
            if (exception == null)
                throw new ArgumentNullException("exception");


            if (string.IsNullOrEmpty(message))
                message = exception.GetType() + ": " + exception.Message;

            message += "\r\nException: " + exception;

            if (message.Length > MaxMessageLength)
                message = message.Substring(0, MaxMessageLength);

            EventLog.WriteEntry(source, message, EventLogEntryType.Error, 0, 0, SerializeException(exception));
        }

        private static byte[] SerializeException(Exception exception) {
            if (exception == null)
                return null;

            var xmlSettings = new XmlWriterSettings {
                Indent = true,
                Encoding = Encoding.UTF8,
                OmitXmlDeclaration = false
            };

            using (var memStream = new MemoryStream())
            using (var xmlWriter = XmlWriter.Create(memStream, xmlSettings)) {
                ExceptionSerializer.SerializeException(
                    null, exception,
                    ExceptionSerializationOptions.MaximumSerialization | ExceptionSerializationOptions.SafeMode,
                    xmlWriter);

                xmlWriter.Flush();
                return memStream.ToArray();
            }
        }
    }
}
